import React, { useState, useEffect, useRef } from 'react';
import { useLocation, useNavigate } from 'react-router-dom';
import { Card, Form, Input, Cascader, Button, message } from 'antd';
import { ArrowLeftOutlined } from '@ant-design/icons';
import { reqCategory, AxiosResponse, DataStatus, reqAddUpdateProduct } from '../../../api';
import PicturesWall from './PicturesWall';
import RichTextEditor from './RichTextEditor';

interface DataNode { // Cascader loadData property type   
    label: React.ReactNode;
    /** Customize hover title */
    title?: string;
    value: string | number;
    disabled?: boolean;
    children?: DataNode[];
    isLeaf?: boolean;
}

type PartProduct = {
    pCategoryId: string;
    categoryId: string;
}

type DataSource = {
    "parentId": string;
    "_id": string;
    "name": string;
    "__v": number;
};
type Status = {
    status: DataStatus.sucess;
    data: DataSource[];
} | {
    status: DataStatus.failure;
    msg: string;
};

type FormItemLayout = {
    labelCol: {
        xs: { span: number };
        sm: { span: number };
    };
    wrapperCol: {
        xs: { span: number };
        sm: { span: number };
    };
};

type FieldName = 'name' | 'desc' | 'price';
type FieldByName = Record<FieldName, string> & {
    categoryIds: [string, string?];
};

type OptionList = {
    value: React.ReactText;
    label: React.ReactNode;
    isLeaf?: boolean;
    loading?: boolean;
    children?: OptionList[];
};

enum Amount {
    Zero
}

const { Item, useForm } = Form;
const { TextArea } = Input;

// Product 添加和更新的子路由组件
const ProductAddUpdate: React.FC = () => {
    const [options, setOptions] = useState<OptionList[]>([]);
    const uploadedImgsRef = useRef<(() => string[]) | null>(null);
    const editorRef = useRef<(() => string) | null>(null);
    const { state: product } = useLocation();
    const navigate = useNavigate();
    const [form] = useForm();
    const isUpdate: boolean = !!product;
    const handleBack = (): void => {
        navigate(-1);
    };
    const handleValidatePrice = (_: unknown, value: string): Promise<void> => {
        const price: number = +value || Amount.Zero;
        let msg: string = '';
        if (!value) {
            msg = '必须输入商品价格';
        } else if (price <= Amount.Zero) {
            msg = '价格必须大于0';
        }
        return !msg ? Promise.resolve() : Promise.reject(new Error(msg));
    };
    const getAsyncCategorys = async (parentId: string): Promise<DataSource[] | void> => {
        const { data }: AxiosResponse<Status> = await reqCategory(parentId);
        if (data.status === DataStatus.sucess) {
            if (parentId !== '0') return data.data;
            const initOptions = async (categorys: DataSource[]): Promise<void> => {
                const optionLists: OptionList[] = categorys.map(({ _id, name }) => ({
                    value: _id,
                    label: name,
                    isLeaf: false
                }));
                if (isUpdate) {
                    const { pCategoryId, categoryId }: PartProduct = product;
                    const isParentId: boolean = pCategoryId === '0';
                    const parentOrSubId: string = isParentId ? categoryId : pCategoryId;
                    const category: DataSource | undefined = categorys.find(({ _id }) => _id === parentOrSubId);
                    const categoryIds: string[] = [category!._id];
                    if (!isParentId) {
                        const { data }: AxiosResponse<Status> = await reqCategory(pCategoryId);
                        if (data.status === DataStatus.sucess) {
                            const childOptions: OptionList[] = data.data.map(({ name, _id }) => ({
                                value: _id,
                                label: name,
                                isLeaf: true
                            }));
                            const subCategory: DataSource | undefined = data.data.find(({ _id }) => _id === categoryId);
                            categoryIds.push(subCategory!._id);
                            const targetOption: OptionList | undefined = optionLists.find(({ value }) => value === pCategoryId);
                            if (targetOption !== undefined) {
                                targetOption.children = childOptions;
                            }
                        }
                    }
                    form.setFieldsValue({
                        categoryIds
                    });
                }
                setOptions([...optionLists]);
            };
            initOptions(data.data);
        }
    };
    const loadData = async (selectedOptions: OptionList[]): Promise<void> => {
        const targetOption = selectedOptions[0];
        targetOption.loading = true;
        const subCategorys: DataSource[] | void = await getAsyncCategorys(targetOption.value as string);
        targetOption.loading = false;
        if (Array.isArray(subCategorys) && subCategorys.length > 0) {
            targetOption.children = subCategorys.map(({ _id, name }) => ({
                value: _id,
                label: name,
                isLeaf: true
            }));
        } else {
            targetOption.isLeaf = true;
        }
        setOptions([...options]);
    };
    const onFinish = async ({ name, desc, price, categoryIds }: FieldByName): Promise<void> => {
        const uploadedImgs: string[] | undefined = uploadedImgsRef.current?.();
        const editorText: string | undefined = editorRef.current?.();
        let pCategoryId: string, categoryId: string;
        if (typeof categoryIds[1] === 'string') {
            [pCategoryId, categoryId] = categoryIds;
        } else {
            pCategoryId = '0';
            [categoryId] = categoryIds;
        }
        const newProduct: Omit<FieldByName, 'categoryIds'> & {
            imgs: string[];
            detail: string;
            _id?: string;
            pCategoryId: string;
            categoryId: string;
        } = { name, desc, price, imgs: uploadedImgs!, detail: editorText!, pCategoryId, categoryId };
        if (isUpdate) {
            newProduct._id = product._id;
        }
        const { data }: AxiosResponse = await reqAddUpdateProduct(newProduct);
        const msg: string = `${isUpdate ? '更新' : '添加'}商品`;
        if (data.status === 0) {
            message.success(`${msg}成功`);
            navigate(-1);
            return;
        }
        message.error(`${msg}失败`);
    };
    const title: React.ReactNode = (
        <span>
            <Button
                type="link"
                style={{
                    marginRight: 10,
                    color: 'green',
                    fontSize: 16
                }}
                onClick={handleBack}
            >
                <ArrowLeftOutlined />
            </Button>
            <span>{isUpdate ? '修改' : '添加'}商品</span>
        </span>
    );
    const formItemLayout: FormItemLayout = {
        labelCol: {
            xs: { span: 24 },
            sm: { span: 2 },
        },
        wrapperCol: {
            xs: { span: 24 },
            sm: { span: 8 },
        },
    };
    useEffect(() => {
        getAsyncCategorys('0');
        // eslint-disable-next-line
    }, []);
    return (
        <Card title={title}>
            <Form {...formItemLayout} onFinish={onFinish} form={form}>
                <Item name="name" label="商品名称" initialValue={product?.name} rules={[
                    { required: true, message: '必须输入商品名称' }
                ]}>
                    <Input placeholder="请输入商品名称" />
                </Item>
                <Item name="desc" label="商品描述" initialValue={product?.desc} rules={[
                    { required: true, message: '必须输入商品描述' }
                ]}>
                    <TextArea placeholder="请输入商品描述" autoSize={{ minRows: 2, maxRows: 6 }} />
                </Item>
                <Item name="price" label="商品价格" initialValue={product?.price} rules={[
                    { required: true, validator: handleValidatePrice }
                ]}>
                    <Input type="number" placeholder="请输入商品价格" addonAfter="元" />
                </Item>
                <Item name="categoryIds" label="商品分类" rules={[
                    { required: true, message: '必须输入商品分类' }
                ]}>
                    <Cascader options={options} loadData={(selectedOptions: DataNode[]): void => {
                        loadData(selectedOptions);
                    }} />
                </Item>
                <Item label="商品图片">
                    <PicturesWall uploadedImgsRef={uploadedImgsRef} imgs={isUpdate && product.imgs} />
                </Item>
                <Item label="商品详情" labelCol={{ span: 2 }} wrapperCol={{ span: 24 }}>
                    <RichTextEditor editorRef={editorRef} detail={isUpdate && product.detail} />
                </Item>
                <Item>
                    <Button type="primary" htmlType="submit">提交</Button>
                </Item>
            </Form>
        </Card>
    );
};

export default ProductAddUpdate;